package recherche;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class ModeleBooleen extends Modele{


private static final String OPE_AND = "AND";
private static final String OPE_OR = "OR";
private static final int LIMITE = 20;

public ModeleBooleen(ArrayList<String> req) {
		super(req);
	}


@Override
public HashMap<String, String> execute(HashMap<String, HashMap<Integer, Integer>> dfs,HashMap<Integer, ArrayList<String>> urlTitle) {
	this.tfIdf(urlTitle, dfs);
	HashMap< Integer,HashMap<Integer,Double>> myReq = this.transformReq();
	String operator= null;
	HashMap<Integer,Double> docMot1 = null;
	HashMap<Integer,Double> docMot2 = null;
	
	HashMap<Integer, Double> rsv  = new HashMap<Integer, Double>();
	if(requeteNorm.size() ==1){
		docMot1 = tfIdfMap.get(requeteNorm.get(0));
		rsv = docMot1;
		
	}
	else{
		for(int i=0; i<requeteNorm.size()-1; i++){
			if(requeteNorm.get(i).equalsIgnoreCase(OPE_AND)){
				if(myReq.get(i-1) == null){
					docMot1 = tfIdfMap.get(requeteNorm.get(i-1));
				}
				else{
					docMot1 = myReq.get(i-1);
				}
				docMot2 = tfIdfMap.get(requeteNorm.get(i+1));
				
				rsv = calculAND(docMot1,docMot2);
				myReq.put(i-1, rsv);
				myReq.put(i+1, rsv);
			
			}
		}
		
		
		for(int i=0; i<requeteNorm.size()-1; i++){
			if(requeteNorm.get(i).equalsIgnoreCase(OPE_OR)){
				
				if(myReq.get(i-1) == null){
					docMot1 = tfIdfMap.get(requeteNorm.get(i-1));
				}
				else{
					docMot1 = myReq.get(i-1);
				}
				if(myReq.get(i+1) == null){
					docMot2 = tfIdfMap.get(requeteNorm.get(i+1));
				}
				else{
					docMot2 = myReq.get(i+1);
				}
				
				rsv = calculOR(docMot1,docMot2);
			}
			
			
		}
	}
	// Ajout des entrées de la map à une liste		 
	List<Entry<Integer, Double>> entries = new ArrayList<Map.Entry<Integer,Double>>(rsv.entrySet());
	Collections.sort(entries, new Comparator<Entry<Integer, Double>>() {
		public int compare(final Entry<Integer, Double> e1, final Entry<Integer, Double> e2) {
			return -(e1.getValue().compareTo(e2.getValue()));
		}
	});
	
	System.out.println("nb resultat :" + entries.size());
	
	if (entries.size()>21)
		entries.subList(20, entries.size()-1).clear();
	
	/*for (Entry<Integer, Double> e : entries){
		System.out.println("doc : "+e.getKey() + "-sim : "+e.getValue());
		
	}*/
	
	
	return chercheDoc(entries, urlTitle);
}

/**
 * 	Creation de la liste des resultats avec le titre et l'url du document
 * @param tabRSV
 * @param urlTitre
 * @return
 */
	private HashMap<String, String> chercheDoc(List<Entry<Integer, Double>> tabRSVtrie, HashMap<Integer, ArrayList<String>> urlTitre) {
		HashMap<String, String> result = new HashMap<String, String>();
		
		for (Entry<Integer, Double> entry : tabRSVtrie) {
			if (entry.getKey().equals(-1))
		    	continue;
		    ArrayList<String> docInfo = urlTitre.get(entry.getKey());
			System.out.println("doc : "+entry.getKey() + "-sim : "+entry.getValue());
			result.put(docInfo.get(0),docInfo.get(1));
		    
		}
		
		return result;
	}

	/**
	 * On recup�re les 10 meilleurs r�sultats
	 * @param idDoc
	 * @param res
	 * @param tabRSV
	 */
	private void compareResult(Integer idDoc,double res, HashMap<Integer, Double> tabRSV){
		HashMap<Integer, Double> tabBis = (HashMap<Integer, Double>) tabRSV.clone();
		for(Map.Entry<Integer, Double> map : tabBis.entrySet()){
			if(map.getValue() < res){
				tabRSV.remove(map.getKey());
				tabRSV.put(idDoc,res);
				
			}
		}
		
	
	
	}

	
	/**
	 * Le calcul pour l'operateur OR
	 * @param docMot1
	 * @param docMot2
	 * @return
	 */
	private HashMap<Integer, Double> calculOR(HashMap<Integer, Double> docMot1,HashMap<Integer, Double> docMot2) {
		HashMap<Integer, Double> tabRSV = new HashMap<Integer, Double>();
		
		Iterator it1 = docMot1.entrySet().iterator();
		calculRSVOR(it1, docMot2, tabRSV);
	
		Iterator it2 = docMot2.entrySet().iterator();
		calculRSVOR(it2, docMot1,tabRSV);
		
		
	
	return tabRSV;
	}



/**
 * Calcul pour chaque document des mots passes en parametre
 * @param it1
 * @param docMot
 * @param tabRSV
 */
	private void calculRSVOR(Iterator it1, HashMap<Integer, Double> docMot,
			HashMap<Integer, Double> tabRSV) {
		double rsv = 0.0;
		double a,b;
		double norm =0.0;
		while (it1.hasNext()){
			
			Map.Entry entry1  = (Map.Entry)it1.next();
			Double x = (Double)entry1.getValue();
			Double y = 0.0;
			y = docMot.get(entry1.getKey());
			if(y == null){
				y = 0.0;
			}
			
			a= Math.pow((x), 2);
			b=Math.pow((y), 2);
		
			rsv = Math.sqrt((a+b)/2);
			
			
			norm = Math.sqrt(x*x + y*y);
			
			rsv= rsv/norm;
			
			
			tabRSV.put((Integer)entry1.getKey(), rsv);
			
		}
	
			
	}



	/**
	 * calcul pour l'operateur AND
	 * @param docMot1
	 * @param docMot2
	 * @return
	 */

	private HashMap<Integer, Double> calculAND(HashMap<Integer,Double> docMot1, HashMap<Integer,Double> docMot2){
		HashMap<Integer, Double> tabRSV = new HashMap<Integer, Double>();
				
	
			Iterator it1 = docMot1.entrySet().iterator();
			calculRSVAND(it1, docMot2, tabRSV);
			
		
			Iterator it2 = docMot2.entrySet().iterator();
			calculRSVAND(it2, docMot1,tabRSV);
			

		
		return tabRSV;
	}



	/**
	 * calcul pour chaque mots passes en parametre
	 * @param it
	 * @param docMot
	 * @param tabRSV
	 */
	private void calculRSVAND(Iterator it, HashMap<Integer,Double> docMot, HashMap<Integer, Double> tabRSV){
		double a = 0;
		double b = 0;
		double rsv = 0;
		double norm=0.0;

		while (it.hasNext()){
			
			Map.Entry entry1  = (Map.Entry)it.next();
			Double x = (Double)entry1.getValue();
			Double y = 0.0;
			y = docMot.get(entry1.getKey());
			if(y == null){
				y = 0.0;
			}
			
			
			
			
			a= Math.pow((1-x), 2);
			b=Math.pow((1-y), 2);
			
			rsv = 1 - Math.sqrt((a+b)/2);
			
			norm = Math.sqrt(x*x + y*y);
			
			rsv= rsv/norm;
			
			tabRSV.put((Integer)entry1.getKey(), rsv);
			
		}
		
	}
	
	
	/**
	 * Transforme la requeteNorm en hasMap pour le calcul du poids 
	 * @return hashmap avec le terme et son poids calcule 
	 */
	private  HashMap<Integer,HashMap<Integer,Double>> transformReq(){
		HashMap< Integer,HashMap<Integer,Double>> mapIdfs = new HashMap<Integer, HashMap<Integer,Double>>();
		for(int i=0; i<requeteNorm.size()-1;i++){
			mapIdfs.put(i,null);
		}
		return mapIdfs;
	}
	
}
